{***************************************************************
    SpyGestion  Copyright (C) 2008 Christophe KOALI <nature2gas@gmail.com>
    
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    
****************************************************************}
unit modParsingClassIHeader;

interface

uses modParsingClassBase,
     modBaseType,
     Classes,
     modLinkOtherPlanet,
     sFonctionsChaines,
     SysUtils,
     Windows,
    

     LibXmlParser;

type

    TParsingHeader = class(IParsingRedirection)
    private

       //
       // Informations qui vont être extraites
       //

       // Lien de changement vers les autres planètes
       FOtherPlanetLink : TCollectionLinkOtherPlanete;
       FOtherPlanetLinkBackup : TCollectionLinkOtherPlanete;


       FCurrentRessource: TOGRessourceAll;
       FCurrentPlanete  : TPlanetLocation;
       FCurrentPlaneteNom: string;

       FExistOfficier: boolean;
       FExistCommandant: boolean;



       //
       // Variables qui vont aider à se repérer dans la page
       //


       FInSelect : boolean;
       FInOption : integer;

       FCheckCondition: integer;

       FCurrLigne: integer;
       FCurrColonne: integer;

       FWitchLigneIsGood: integer;
       FWitchColonneIsGood: integer;

       

       //
       // Variables qui vont aider à l'extraction des données
       //

       FTamponForEnergie: string;
       FTamponDejaTraite: boolean;

       // avec la v76, il y a des balises entre les balises options
       // cela empêche d'avoir le nom de la planete de les coordonnées en meme temps
       // c'est un avantage, car on a d'un coté le nom de la planète, de l'autre les coordonnées
       // mais cela ne correspond pas au système actuel
       // au lieu de modifier et de chercher à savoir dans quelle sous balise on est,
       // on place tous dans un tampon et on utilise la méthode habituelle d'analyse
       FTamponForOption: string;


       FLastLinkPlaneteInfo: TLinkOtherPlanete;


       FCheckingOfficierDone: boolean;

       

       procedure TraitementTamponEnergie;

       function GetPlaneteStr: string;



       procedure OnOptionData(Content: string);

       procedure DoDebugMinerai(const Msg: string);

    public

       //
       // Accès aux informations extraites
       //

       property ExistOfficier  : boolean  read FExistOfficier;
       property ExistCommandant: boolean  read FExistCommandant;

       // Planète courante, informations extraites à partir du menu déroulant
       property Planete     : TPlanetLocation  read FCurrentPlanete;
       property PlaneteStr  : string           read GetPlaneteStr;              // la location en String
       property PlaneteNom  : string           read FCurrentPlaneteNom;


       property CurrRessource: TOGRessourceAll read FCurrentRessource;

       
       // Pour accéder aux liens des autres planètes
       property AutrePlanete : TCollectionLinkOtherPlanete read FOtherPlanetLink;


       procedure BackupCreate;
       procedure BackupRestaure;



       /////////////////////////////////////////////////////////////////////////
       // Implémentation de IParsingRedirection

        // initialise l'interface
        procedure Initialisation; override;

        // obtient le résultat d'analyse
        function  GetFinalState: TParsingResultState; override;

        procedure SetFullURLFromBase(const BaseLink: string); override;


        // indique le début et la fin
        //procedure OnStart; override;             // lors du DIV d'ouverture  (non transmis)
        //procedure OnTerminated; override;        // lors du DIV de fermeture (non transmis)

        procedure ScanOnStartTag(Sender: TObject; TagName: string; Attributes: TAttrList); override;
        procedure ScanOnEndTag(Sender: TObject; TagName: string); override;
        procedure ScanOnContent(Sender: TObject; Content: string); override;

       //
       /////////////////////////////////////////////////////////////////////////




       constructor Create;
       destructor Destroy; override;
    end;


implementation

uses modCore, modLanguageParsing, sHTMLFonctions;

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

procedure TParsingHeader.BackupCreate;
begin
    FOtherPlanetLink.DupliqueTo(FOtherPlanetLinkBackup);
end;

procedure TParsingHeader.BackupRestaure;
begin
    FOtherPlanetLinkBackup.DupliqueTo(FOtherPlanetLink);
end;


procedure TParsingHeader.SetFullURLFromBase(const BaseLink: string);
begin
   FOtherPlanetLink.SetFullURL(BaseLink);

   inherited;

end;

(*
procedure TParsingHeader.OnStart;              // lors du DIV d'ouverture  (non transmis)
begin
    // rien à faire, tout à été fait dans Initialisation
end;

procedure TParsingHeader.OnTerminated;         // lors du DIV de fermeture (non transmis)
begin
    // rien à faire également, la vérification se fera dans GetFinalState
end;
*)

function TParsingHeader.GetFinalState: TParsingResultState;
begin
   Result := PRESULT_ECHEC;

   if FCurrentPlanete.Galaxie < 0  then begin
      exit;
   end;

   if FCurrentRessource.Metal < -50 then begin
      exit;
   end;
   if FCurrentRessource.Cristal < -50 then begin
      exit;
   end;
   if FCurrentRessource.Deuterium < -50 then begin
      exit;
   end;

   if FCurrentPlaneteNom = '' then begin
      exit;
   end;

   // corrige au cas où les ressources seraient négatives sur la page (en particulier sur les lunes)
   if FCurrentRessource.Metal < 0 then begin
      FCurrentRessource.Metal  := 0;
   end;
   if FCurrentRessource.Cristal < 0 then begin
      FCurrentRessource.Cristal  := 0;
   end;
   if FCurrentRessource.Deuterium < 0 then begin
      FCurrentRessource.Deuterium  := 0;
   end;

   Result := NoT(PRESULT_ECHEC);

end;

procedure TParsingHeader.TraitementTamponEnergie;
var xPos: integer;
begin
    if FTamponDejaTraite then exit;

    // -20/1.786
    xPos := pos('/', FTamponForEnergie);

    if xPos = 0 then
       FCurrentRessource.Energie := 0
    else begin
       FTamponForEnergie := copy(FTamponForEnergie, 1, xPos - 1);
       FCurrentRessource.Energie := StrToIntDef(FTamponForEnergie, 0);
    end;

    FTamponDejaTraite := true;
    FTamponForEnergie := '';


end;




procedure TParsingHeader.Initialisation;
begin

    //
    // Initialisation des informations qui vont être extraites
    //

    // stupid game: les ressources peuvent exceptionnellement être négative (sur les lunes)
    // on utilise donc -100 au lieu de -1
    FCurrentRessource.Metal     := -100;
    FCurrentRessource.Cristal   := -100;
    FCurrentRessource.Deuterium := -100;
    FCurrentRessource.Energie   := 0;

    FCurrentPlanete.Galaxie       := -1;
    FCurrentPlanete.SystemSolaire := -1;
    FCurrentPlanete.Position      := -1;

    // Efface les autres planètes
    FOtherPlanetLink.Clear;

    FExistCommandant := false;
    FExistOfficier   := false;

    FCurrentPlaneteNom := '';


    
    //
    // Initialisation des variables qui vont aider à se repérer dans la page
    //


    FInSelect := false;
    FInOption := 0;
    FCheckCondition := 0;

    FWitchLigneIsGood := -1;
    FWitchColonneIsGood := -1;
    
    FCurrLigne  := -1;
    FCurrColonne:= -1;





    //
    // Variables qui vont aider à l'extraction des données
    //

    FTamponForEnergie := '';
    FTamponDejaTraite := false;

    FTamponForOption := '';

    FLastLinkPlaneteInfo.Location.Galaxie    := -1;
    FLastLinkPlaneteInfo.Location.SystemSolaire := -1;
    FLastLinkPlaneteInfo.Location.Position   := -1;
    FLastLinkPlaneteInfo.Lien                := '';

    FCheckingOfficierDone := false;


    
    
    FError := false;

end;


function TParsingHeader.GetPlaneteStr: string;
begin
    Result := mbtPlanetLocationToStr(FCurrentPlanete);
end;


procedure TParsingHeader.ScanOnStartTag(Sender: TObject; TagName: string; Attributes: TAttrList);
var CurrBalise: string;
    xPos : integer;
begin
   TagName := lowercase(TagName);

   if TagName = 'select' then begin
      // Ceci permet de choisir la planète que l'on veut gérer
      // <select  size=1 onchange="haha(this)">
      // <option  value="/game/buildings.php?session=sessionid&cp=1111111&mode=Verteidigung&gid=&messageziel=&re=0" selected>PlaneteNom [1:2:3]</select>
      FInSelect := true;

   end else if TagName = 'option' then begin

      if FInSelect then begin
          CurrBalise := trim(Attributes.Value('selected'));
          FTamponForOption := '';

          if CurrBalise = '1' then
             FInOption := 2
          else begin
             // Sauvegarde le lien
             FInOption := 1;

             FLastLinkPlaneteInfo.Lien := Attributes.Value('value');

          end;

      end;

   end else if TagName = 'table' then begin
      FCurrLigne := 0;
      FCurrColonne := 0;
   end else if TagName = 'tr' then begin
      Inc(FCurrLigne);
      FCurrColonne := 0;

   end else if (TagName = 'td') or (TagName = 'th') then begin
      Inc(FCurrColonne);


   end else if TagName = 'img' then begin
      // detection compte commandant et officiel
      // FExistOfficier
      CurrBalise := trim(Attributes.Value('src'));

      xPos := LastDelimiter('/', CurrBalise);
      if xPos > 0 then begin
         System.Delete(CurrBalise, 1, xPos);

         if SameText(CurrBalise, '') then begin
            // sans: http://yyyyy/game/img/commander_ikon_un.gif
            // avec: http://yyyyy/game/img/commander_ikon.gif
            // Deduction: "un" signifie "sans"
            FExistCommandant := true;

         end else if SameText(CurrBalise, 'admiral_ikon.gif') then begin
            // sans: admiral_ikon_un.gif
            FExistOfficier := true;

         end else if SameText(CurrBalise, 'ingenieur_ikon.gif') then begin
            // sans: ingenieur_ikon_un.gif
            FExistOfficier := true;

         end else if SameText(CurrBalise, 'geologe_ikon.gif') then begin
            // sans: geologe_ikon_un.gif
            FExistOfficier := true;


         end else if SameText(CurrBalise, 'technokrat_ikon.gif') then begin
            // sans: technokrat_ikon_un.gif
            FExistOfficier := true;

         end;

         CurrBalise := lowercase(CurrBalise);

         if pos('_ikon', CurrBalise) > 0 then begin
            FCheckingOfficierDone := true;
         end;

         {$IFDEF OFFICIER_OK}
             //FExistOfficier := false;
         {$ENDIF}



      end;

   end;


end;

procedure TParsingHeader.ScanOnEndTag(Sender: TObject; TagName: string);
begin
   TagName := lowercase(TagName);

   if TagName = 'select' then begin
      FInSelect := false;
      FInOption := 0;

   end else if TagName = 'option' then begin
      // Note: la balise de fin d'option n'existe pas

      if FInSelect then begin
         FTamponForOption := trim(FTamponForOption);
         OnOptionData(FTamponForOption);
         FTamponForOption := '';
      end;


      FInOption := 0;

   end else if TagName = 'table' then begin
      if (FWitchLigneIsGood > 0) and (FCheckingOfficierDone) then begin
          TraitementTamponEnergie;

          // Indique que l'on a finit le traitement
          
      end;

         
   end;

end;


procedure TParsingHeader.OnOptionData(Content: string);
label lDoCheck;
var xPos: integer;
    MoonCertain: boolean;
    MoonPosition: integer;

    peItem: PLinkOtherPlanete;

begin

    Content := trim(Content);

    //DoDebugMinerai(Content);
    

    MoonPosition := pos(lowercase(LangParsing.GetData('header_planetlist_LuneLwPos', 'lune')), lowercase(Content));
    MoonCertain  := false;

    if MoonPosition > 0 then begin
       if pos('(', Content) > 0 then begin
          // c'est une lune
          // car avec la nouvelle version, les lunes peuvent se situées avant les planètes...
          // MAIS uniquement lorsqu'elles sont renommées
          MoonCertain := true;
       end;
    end;


    if FInOption = 2 then begin
       // <option  value="/game/buildings.php?session=00000&cp=11111&mode=Verteidigung&gid=&messageziel=&re=0" selected>
       // PlaneteNom [1:2:3]</select>


       xPos := LastDelimiter(' ', Content);
       if xPos > 0 then begin
           FCurrentPlaneteNom := copy(Content, 1, xPos - 1);
           
           System.Delete(Content, 1, xPos);
           FCurrentPlanete := mpcExtractPlanetLocation(Content);

           if MoonCertain then begin
              FCurrentPlanete.Position := FCurrentPlanete.Position + CNT_POSITION_LUNE;
           end;

           peItem := FOtherPlanetLink.Get_Pointeur(FCurrentPlanete);

           if peItem <> nil then begin
              // la planète est sélectionnée, elle n'est donc pas censée déjà exister
              // dans la liste des planètes
              // SAUF avant lors de la gestion des lunes, mais à présent, elles sont
              // bien gérées...
              // si on arrive ici, c'est qu'il y a forcément une erreur quelque part
              // edit: en fait non, j'avais oublié le cas de lune non renommée qui ne
              // possède pas le caractère "("


              if MoonCertain then begin
                 // bizarre
                 DoDebugMinerai('Attention: la planète sélectionnée existe déjà dans la liste (Identifiée comme lune) - ' + Content);

                    // rectifie celui de l'items
                    if peItem.Location.Position >= CNT_POSITION_LUNE then begin
                       // il a bien le rang de lune
                       // rectifie son rang
                       DoDebugMinerai('Rectification...');
                       peItem.Location.Position := peItem.Location.Position - CNT_POSITION_LUNE;

                    end else begin
                       // sinon erreur...
                       DoDebugMinerai('Erreur: Bizarre 11 - ' + Content);

                    end;



              end else if MoonPosition < 1 then begin
                 // ce n'est pas une lune, ni une lune renommé
                 // donc on ne devrait pas arriver ici
                 // SAUF si la lune est avant et qu'elle
                 // a été identifié en tant que planète (donc une lune non renommée située avant)
                 DoDebugMinerai('Attention: la planète sélectionnée existe déjà dans la liste - ' + Content);


                    // l'élément actuel est bel et bien une planète, c'est l'élément précédent
                    // qui ne l'était pas
                    // on rectifie le tir:
                    if peItem.Location.Position < CNT_POSITION_LUNE then begin
                       // il a bien le rang de planète
                       DoDebugMinerai('Rectification...');
                       peItem.Location.Position := peItem.Location.Position + CNT_POSITION_LUNE;

                    end else begin
                       // a ne rien comprendre...
                       // c'est impossible d'arriver ici
                       DoDebugMinerai('Erreur: Bizarre 12 - ' + Content);

                    end;


              end else begin
                 // sinon MoonPosition >= 1
                 // c'est une lune non renommée dont la planète a déjà été identifié
                 FCurrentPlanete.Position := FCurrentPlanete.Position + CNT_POSITION_LUNE;

                 if (FOtherPlanetLink.Get_Index(FCurrentPlanete)) >= 0 then begin
                     DoDebugMinerai('Erreur: la planète sélectionnée existe déjà dans la liste (et la lune, et la planète) - ' + Content);
                 end;
              end;

           end;


       end else begin
          DoDebugMinerai('Erreur: Espace non trouvé (2) - ' + Content);
       end;


       exit;


    end else if FInOption = 1 then begin
       // TODO: Sauvegarder les autres planéte, pour connaitre le lien pour
       // y accéder
       // <option  value="/game/resources.php?session=111111&cp=00000&mode=&gid=&messageziel=&re=0" >
       // planetName [1:81:15]</select>

       xPos := LastDelimiter(' ', Content);
       if xPos > 0 then begin
           FLastLinkPlaneteInfo.Nom := copy(Content, 1, xPos - 1);
           System.Delete(Content, 1, xPos);
           FLastLinkPlaneteInfo.Location := mpcExtractPlanetLocation(Content);

           if MoonCertain then begin
              FLastLinkPlaneteInfo.Location.Position := FLastLinkPlaneteInfo.Location.Position + CNT_POSITION_LUNE;
           end;


           // Vérifie si le lien est valide (sinon c'est inutile d'ajouter la planète)
           if FLastLinkPlaneteInfo.Lien <> '' then begin

              peItem := FOtherPlanetLink.Get_Pointeur(FLastLinkPlaneteInfo.Location);

              if peItem <> nil then begin
                 // c'est probablement une lune car la location existe déjà
                 // MAIS, ce le problème des lunes est mieux géré
                 // si la planète existe déjà, c'est une erreur
                 //DoDebugMinerai('Erreur: La planète existe déjà - ' + Content);
                 //exit;


lDoCheck:
                 if MoonCertain then begin
                    // bizarre...
                    // sauf si la planète a été identifié comme lune (avec le nom "Lune")
                    // mais ce cas est improbable puisqu'on ajoute en tant que planète
                    // lorsque c'est le cas
                    DoDebugMinerai('Attention: la planète existe déjà dans la liste (Identifiée comme lune) - ' + Content);

                    // rectifie celui de l'items
                    if peItem.Location.Position >= CNT_POSITION_LUNE then begin
                       // il a bien le rang de lune
                       // rectifie son rang
                       DoDebugMinerai('Rectification...');
                       peItem.Location.Position := peItem.Location.Position - CNT_POSITION_LUNE;

                    end else begin
                       // sinon erreur...
                       DoDebugMinerai('Erreur: Bizarre 01 - ' + Content);

                    end;



                 end else if MoonPosition < 1 then begin
                    // ce n'est pas une lune, ni une lune renommée
                    // donc on ne devrait pas arriver ici,
                    // SAUF si la lune est avant et qu'elle
                    // a été identifié en tant que planète (donc une lune non renommée située avant)
                    DoDebugMinerai('Attention: la planète existe déjà dans la liste - ' + Content);

                    // l'élément actuel est bel et bien une planète, c'est l'élément précédent
                    // qui ne l'était pas
                    // on rectifie le tir:
                    if peItem.Location.Position < CNT_POSITION_LUNE then begin
                       // il a bien le rang de planète
                       DoDebugMinerai('Rectification...');
                       peItem.Location.Position := peItem.Location.Position + CNT_POSITION_LUNE;

                    end else begin
                       // a ne rien comprendre...
                       // c'est impossible d'arriver ici
                       DoDebugMinerai('Erreur: Bizarre 02 - ' + Content);

                    end;



                 end else begin
                    // sinon MoonPosition >= 1
                    // c'est une lune non renommée dont la planète a déjà été identifié
                    FLastLinkPlaneteInfo.Location.Position := FLastLinkPlaneteInfo.Location.Position + CNT_POSITION_LUNE;

                    if (FOtherPlanetLink.Get_Index(FLastLinkPlaneteInfo.Location)) >= 0 then begin
                       DoDebugMinerai('Erreur: la planète existe déjà dans la liste (et la lune, et la planète) - ' + Content);
                    end;

                 end;



              end else if CompareLocation(FCurrentPlanete, FLastLinkPlaneteInfo.Location) then begin
                 // c'est probablement une lune (cas où la planète de la lune est la planète courante)
                 // MAIS, encore une fois, le problème des lunes a été mieux géré
                 // normalement on n'arrive jamais ici
                 //DoDebugMinerai('Erreur: La planète possède les mêmes coordonnées que la planète courante - ' + Content);
                 //exit;

                 goto lDoCheck;

                 
                 (*
                 if MoonPossible then begin
                    FLastLinkPlaneteInfo.Location.Position := FLastLinkPlaneteInfo.Location.Position + CNT_POSITION_LUNE;

                 end else begin

                 end;
                 *)


              end;



              FOtherPlanetLink.Add(FLastLinkPlaneteInfo);

              FLastLinkPlaneteInfo.Lien := '';
           end;

       end else begin
          DoDebugMinerai('Erreur: Espace non trouvé (1) - ' + Content);
       end;


    end;


end;

procedure TParsingHeader.ScanOnContent(Sender: TObject; Content: string);
var xPos: integer;

begin

    if FInSelect then begin
       FTamponForOption := FTamponForOption + ' ' + Content;
       exit;
    end;

    Content := lowercase(trim(Content));

    //LangParsing.GetData('renergie', 'energie')


    if SameText(Content, LangParsing.GetData('header_st_metal', 'métal')) then begin
        Inc(FCheckCondition);
        FWitchLigneIsGood := FCurrLigne + 1;
        FWitchColonneIsGood := FCurrColonne;

    end else if SameText(Content, LangParsing.GetData('header_st_cristal', 'cristal')) then begin
        Inc(FCheckCondition);

    end else if SameText(Content, LangParsing.GetData('header_st_deuterium', 'deutérium')) then begin

        Inc(FCheckCondition);
    end;


    if FCurrLigne = FWitchLigneIsGood then begin
       case FCurrColonne of
            1: FCurrentRessource.Metal     := StrToIntDef(sfcRemplace(Content, '.', ''), -100);
            2: FCurrentRessource.Cristal   := StrToIntDef(sfcRemplace(Content, '.', ''), -100);
            3: FCurrentRessource.Deuterium := StrToIntDef(sfcRemplace(Content, '.', ''), -100);
            5: begin
                  FTamponForEnergie := FTamponForEnergie + Content;
               end;

            6: TraitementTamponEnergie;  // si il n'y a pas d'autre cellule, il sera traité ailleurs

       end;

    end;



end;













procedure TParsingHeader.DoDebugMinerai(const Msg: string);
begin
    {$IFDEF DEBUG_PARSING}
          DoDebugContent('Header -> ' + Msg);
    {$ENDIF}
end;



constructor TParsingHeader.Create;
begin
    inherited Create;

    FOtherPlanetLink       := TCollectionLinkOtherPlanete.Create;
    FOtherPlanetLinkBackup := TCollectionLinkOtherPlanete.Create;

end;

destructor TParsingHeader.Destroy;
begin
    FOtherPlanetLink.Free;
    FOtherPlanetLinkBackup.Free;

    inherited Destroy;
end;


end.
